#!/bin/sh
# soluty's Arch Boot Script
# by soluty <soluty@mail.soluty.cc>
# Inspired by LukeSmithxyz/LARBS
# License: GNU GPLv3

### OPTIONS AND VARIABLES ###
while getopts "r:b:p:hf" o; do case "${o}" in
	h) printf "Optional arguments for custom use:\\n  -r: Dotfiles repository (local file or url)\\n  -f: full install, contains package tag with F, only use pacman\\n  -p: Dependencies and programs csv (local file or url)\\n  -a: AUR helper (must have pacman-like syntax)\\n  -h: Show this message\\n" && exit 1 ;;
	r) dotfilesrepo=${OPTARG} && git ls-remote "$dotfilesrepo" || exit 1 ;;
	b) repobranch=${OPTARG} ;;
	p) progsfile=${OPTARG} ;;
	f) fullinstall="a" ;;
	*) printf "Invalid option: -%s\\n" "$OPTARG" && exit 1 ;;
esac done

boxtitle="Arch Boot Script"
[ -z "$dotfilesrepo" ] && dotfilesrepo="https://e.coding.net/soluty/dotfiles.git"
[ -z "$progsfile" ] && progsfile="https://gitee.com/soluty/archboot/raw/master/progs.csv"
[ -z "$repobranch" ] && repobranch="master"
[ -z "$fullinstall" ] && fullinstall=""
aurhelper="yay"
# [ -z "$aurhelper" ] && aurhelper="yay"

        
### FUNCTIONS ###
installpkg(){ pacman --noconfirm --needed -S "$1" >/dev/null 2>&1 ;}

fullinstallpkg() { [ -z "$fullinstall" ] || pacman --noconfirm --needed -S "$1" >/dev/null 2>&1 ; }

error() { printf "%s\n" "$1" >&2; exit 1; }

welcomemsg() { \
	dialog --title "Welcome!" --msgbox "Welcome to soluty's Arch Boot Script!\\n\\nThis script will automatically install a fully-featured Linux desktop, which I use as my main machine.\\n\\n-soluty" 10 60

	dialog --colors --title "Important Note!" --yes-label "All ready!" --no-label "Return..." --yesno "Be sure the computer you are using has current pacman updates and refreshed Arch keyrings.\\n\\nIf it does not, the installation of some programs might fail." 8 70
}

change_pacman_mirrorlist() {\
	[ -x "$(command -v "reflector")" ] || installpkg reflector >/dev/null 2>&1
	yes | reflector -c China --sort delay --save /etc/pacman.d/mirrorlist
}

getuserandpass() { \
	# Prompts user for new username an password.
	name=$(dialog --inputbox "First, please enter a name for the user account." 10 60 3>&1 1>&2 2>&3 3>&1) || exit 1
	while ! echo "$name" | grep -q "^[a-z_][a-z0-9_-]*$"; do
    	name=$(dialog --no-cancel --inputbox "Username not valid. Give a username beginning with a letter, with only lowercase letters, - or _." 10 60 3>&1 1>&2 2>&3 3>&1)
	done
	pass1=$(dialog --no-cancel --passwordbox "Enter a password for that user." 10 60 3>&1 1>&2 2>&3 3>&1)
	pass2=$(dialog --no-cancel --passwordbox "Retype password." 10 60 3>&1 1>&2 2>&3 3>&1)
	while ! [ "$pass1" = "$pass2" ]; do
		unset pass2
		pass1=$(dialog --no-cancel --passwordbox "Passwords do not match.\\n\\nEnter password again." 10 60 3>&1 1>&2 2>&3 3>&1)
		pass2=$(dialog --no-cancel --passwordbox "Retype password." 10 60 3>&1 1>&2 2>&3 3>&1)
	done ;
}

usercheck() { \
	! { id -u "$name" >/dev/null 2>&1; } ||
	dialog --colors --title "WARNING!" --yes-label "CONTINUE" --no-label "No wait..." --yesno "The user \`$name\` already exists on this system. LARBS can install for a user already existing, but it will \\Zboverwrite\\Zn any conflicting settings/dotfiles on the user account.\\n\\nLARBS will \\Zbnot\\Zn overwrite your user files, documents, videos, etc., so don't worry about that, but only click <CONTINUE> if you don't mind your settings being overwritten.\\n\\nNote also that LARBS will change $name's password to the one you just gave." 14 70
}

preinstallmsg() { \
	dialog --title "Let's get this party started!" --yes-label "Let's go!" --no-label "No, nevermind!" --yesno "The rest of the installation will now be totally automated, so you can sit back and relax.\\n\\nIt will take some time, but when done, you can relax even more with your complete system.\\n\\nNow just press <Let's go!> and the system will begin installation!" 13 60 || { clear; exit 1; }
}

adduserandpass() { \
	# Adds user `$name` with password $pass1.
	dialog --infobox "Adding user \"$name\"..." 4 50
	useradd -m -g wheel -s /bin/zsh "$name" >/dev/null 2>&1 ||
	usermod -a -G wheel "$name" && mkdir -p /home/"$name" && chown "$name":wheel /home/"$name"
	export repodir="/home/$name/.local/src"; mkdir -p "$repodir"; chown -R "$name":wheel "$(dirname "$repodir")"
	echo "$name:$pass1" | chpasswd
	unset pass1 pass2 ;
}

refreshkeys() { \
	case "$(readlink -f /sbin/init)" in
		*systemd* )
			dialog --infobox "Refreshing Arch Keyring..." 4 40
			pacman --noconfirm -S archlinux-keyring >/dev/null 2>&1
			;;
		*)
			dialog --infobox "Enabling Arch Repositories..." 4 40
			pacman --noconfirm --needed -S artix-keyring artix-archlinux-support >/dev/null 2>&1
			for repo in extra community; do
				grep -q "^\[$repo\]" /etc/pacman.conf ||
					echo "[$repo]
Include = /etc/pacman.d/mirrorlist-arch" >> /etc/pacman.conf
			done
			pacman -Sy >/dev/null 2>&1
			pacman-key --populate archlinux
			;;
	esac ;}

newperms() { # Set special sudoers settings for install (or after).
	sed -i "/#SOLUTY/d" /etc/sudoers
	echo "$* #SOLUTY" >> /etc/sudoers ;}

installyay() { # Installs yay from download bin
	dialog --infobox "Installing yay, an AUR helper..." 4 50
	curl -O "https://gitee.com/soluty/archboot/raw/master/yay"
	cp yay /usr/bin/
}

installvmtools() { # 检测是不是vmware虚拟机,是的话就安装open-vm-tools
	dmidecode -s system-product-name | grep -q "VMware" && installpkg open-vm-tools
}

enablesystemservice() { # 启动某些系统服务
	# 启动vmware虚拟机相关服务
	dmidecode -s system-product-name | grep -q "VMware" && systemctl enable vmtoolsd 
	dmidecode -s system-product-name | grep -q "VMware" && systemctl enable vmware-vmblock-fuse
	dmidecode -s system-product-name | grep -q "VMware" && vmware-user start
}

# 这个在xfce似乎不起作用
setsystemxkb() { 	# 设置系统级别的layout
	printf 'Section "InputClass"
        Identifier "system-keyboard"
        MatchIsKeyboard "on"
        Option "XkbLayout" "us"
        Option "XkbVariant" "norman"
EndSection' > /etc/X11/xorg.conf.d/00-keyboard.conf
}

manualinstall() { # Installs $1 manually. Used only for AUR helper here.
	# Should be run after repodir is created and var is set.
	dialog --infobox "Installing \"$1\", an AUR helper..." 4 50
	sudo -u "$name" mkdir -p "$repodir/$1"
	sudo -u "$name" git clone --depth 1 "https://aur.archlinux.org/$1.git" "$repodir/$1" >/dev/null 2>&1 ||
		{ cd "$repodir/$1" || return 1 ; sudo -u "$name" git pull --force origin master;}
	cd "$repodir/$1"
	sudo -u "$name" -D "$repodir/$1" makepkg --noconfirm -si >/dev/null 2>&1 || return 1
}

maininstall() { # Installs all needed programs from main repo.
	dialog --title boxtitle --infobox "Installing \`$1\` ($n of $total). $1 $2" 5 70
	installpkg "$1"
	}

mainfullinstall() { # Installs all needed programs from main repo.
	dialog --title boxtitle --infobox "Installing \`$1\` ($n of $total). $1 $2" 5 70
	fullinstallpkg "$1"
	}

gitmakeinstall() {
	progname="$(basename "$1" .git)"
	dir="$repodir/$progname"
	dialog --title boxtitle --infobox "Installing \`$progname\` ($n of $total) via \`git\` and \`make\`. $(basename "$1") $2" 5 70
	sudo -u "$name" git clone --depth 1 "$1" "$dir" >/dev/null 2>&1 || { cd "$dir" || return 1 ; sudo -u "$name" git pull --force origin master;}
	cd "$dir" || exit 1
	make >/dev/null 2>&1
	make install >/dev/null 2>&1
	cd /tmp || return 1 ;}

aurinstall() { \
	dialog --title boxtitle --infobox "Installing \`$1\` ($n of $total) from the AUR. $1 $2" 5 70
	echo "$aurinstalled" | grep -q "^$1$" && return 1
	sudo -u "$name" $aurhelper -S --noconfirm "$1" >/dev/null 2>&1
	}

pipinstall() { \
	dialog --title boxtitle --infobox "Installing the Python package \`$1\` ($n of $total). $1 $2" 5 70
	[ -x "$(command -v "pip")" ] || installpkg python-pip >/dev/null 2>&1
	yes | pip install "$1"
	}

registergoscript() { # https://studygolang.com/articles/12461
	[ -x /usr/local/bin/gorun  ] || ln -s "/home/$name/go/bin/gorun" /usr/local/bin/gorun
	[ -f /proc/sys/fs/binfmt_misc  ] || echo ':golang:E::go::/usr/local/bin/gorun:OC' | sudo tee /proc/sys/fs/binfmt_misc/register
}

golanginstall() { \
	dialog --title boxtitle --infobox "Installing the Golang package \`$1\` ($n of $total). $1 $2" 5 70
	[ -x "$(command -v "go")" ] || installpkg go >/dev/null 2>&1
	yes | PATH=https://goproxy.cn,direct go install "$1"
	}

installationloop() { \
	([ -f "$progsfile" ] && cp "$progsfile" /tmp/progs.csv) || curl -Ls "$progsfile" | sed '/^#/d' > /tmp/progs.csv
	total=$(wc -l < /tmp/progs.csv)
	aurinstalled=$(pacman -Qqm)
	while IFS=, read -r tag program comment; do
		n=$((n+1))
		echo "$comment" | grep -q "^\".*\"$" && comment="$(echo "$comment" | sed "s/\(^\"\|\"$\)//g")"
		case "$tag" in
			"A") aurinstall "$program" "$comment" ;;
			"G") gitmakeinstall "$program" "$comment" ;;
			"GO") golanginstall "$program" "$comment" ;;
			"P") pipinstall "$program" "$comment" ;;
			"M") maininstall "$program" "$comment" ;;
			"F") mainfullinstall "$program" "$comment" ;;
			*) echo ignore "$program" "$comment" ;;
		esac
	done < /tmp/progs.csv ;}

putgitrepo() { # Downloads a gitrepo $1 and places the files in $2 only overwriting conflicts
	dialog --infobox "Downloading and installing config files..." 4 60
	[ -z "$3" ] && branch="master" || branch="$repobranch"
	dir=$(mktemp -d)
	[ ! -d "$2" ] && mkdir -p "$2"
	chown "$name":wheel "$dir" "$2"
	sudo -u "$name" git clone --recursive -b "$branch" --depth 1 --recurse-submodules "$1" "$dir" >/dev/null 2>&1
	sudo -u "$name" cp -rfT "$dir" "$2"
	}

systembeepoff() { dialog --infobox "Getting rid of that retarded error beep sound..." 10 50
	rmmod pcspkr
	echo "blacklist pcspkr" > /etc/modprobe.d/nobeep.conf ;}

finalize(){ \
	dialog --infobox "Preparing welcome message..." 4 50
	dialog --title "All done!" --msgbox "Congrats! Provided there were no hidden errors, the script completed successfully and all the programs and configuration files should be in place.\\n\\nTo run the new graphical environment, log out and log back in as your new user, then run the command \"startx\" to start the graphical environment (it will start automatically in tty1).\\n\\n.t Soluty" 12 80
	}

### THE ACTUAL SCRIPT ###

### This is how everything happens in an intuitive format and order.

# 检测用户是不是root, 安装dialog包, 用来提供终端下的提示.
pacman --noconfirm --needed -Sy dialog || error "Are you sure you're running this as the root user, are on an Arch-based distribution and have an internet connection?"

# 欢迎和提示信息
welcomemsg || error "User exited."

# 获取用户名和密码
getuserandpass || error "User exited."

# 如果用户已经存在, 给一个警告, 看是不是继续安装
usercheck || error "User exited."

# 安装之前最后一次用户反悔的机会.
preinstallmsg || error "User exited."

### 下面的脚本不再需要用户输入的参与

# 更新arch的keyring.
refreshkeys || error "Error automatically refreshing Arch keyring. Consider doing so manually."

# 修改pacman的镜像为靠近中国的镜像
dialog --title boxtitle --infobox "change pacman mirrorlist to china, wait a moment ..." 3 70
change_pacman_mirrorlist

# 安装构建过程中必须的软件, curl和git用来远程下载文件, base-devel是c语言的基础包,ca-certificates包含一些常见的数字签名, ntp是时间同步工具
for x in curl ca-certificates base-devel git ntp; do
	dialog --title boxtitle --infobox "Installing \`$x\` which is required to install and configure other programs." 5 70
	installpkg "$x"
done

# ntp时间同步
# dialog --title boxtitle --infobox "Synchronizing system time to ensure successful and secure installation of software..." 4 70
# ntpdate 0.us.pool.ntp.org >/dev/null 2>&1
timedatectl set-ntp true

adduserandpass || error "Error adding username and/or password."

[ -f /etc/sudoers.pacnew ] && cp /etc/sudoers.pacnew /etc/sudoers # Just in case

# 允许用户不用密码运行sudo,因为yay之类的软件需要这个
newperms "%wheel ALL=(ALL) NOPASSWD: ALL"

# 让pacman有颜色, 并发下载改为8, 并且有吃豆人的图标
grep -q "ILoveCandy" /etc/pacman.conf || sed -i "/#VerbosePkgLists/a ILoveCandy" /etc/pacman.conf
sed -i "s/^#ParallelDownloads = 8$/ParallelDownloads = 5/;s/^#Color$/Color/" /etc/pacman.conf

# 编译时使用所有的核心数  假设你是8核处理器, 则将/etc/makepkg.conf 中的 #MAKEFLAGS="-j2" 一行替换为 MAKEFLAGS="-j8"
sed -i "s/-j2/-j$(nproc)/;s/^#MAKEFLAGS/MAKEFLAGS/" /etc/makepkg.conf


# 手动安装yay
# [ -x "$(command -v "yay")" ] || manualinstall yay || error "Failed to install AUR helper."
[ -x "$(command -v "yay")" ] || installyay || error "Failed to install AUR helper."

# 下载所有的软件. 读取progs.csv文件, 必须要用户可以无密码的使用sudo的时候才能正确安装
installationloop

# 如果是在vmware中设置,则安装open-vm-tools
installvmtools
enablesystemservice

dialog --title boxtitle --infobox "Finally, installing \`libxft-bgra\` to enable color emoji in suckless software without crashes." 5 70
yes | sudo -u "$name" $aurhelper -S libxft-bgra-git >/dev/null 2>&1

# 注册gorun让./go文件脚本使用正常
dialog --title boxtitle --infobox "Register to make go script work well" 5 70
registergoscript

# 安装dotfiles配置目录
putgitrepo "$dotfilesrepo" "/home/$name" "$repobranch"
rm -f "/home/$name/README.md"
# Create default urls file if none exists.
# [ ! -f "/home/$name/.config/newsboat/urls" ] && echo "http://lukesmith.xyz/rss.xml
# https://notrelated.libsyn.com/rss
# https://www.youtube.com/feeds/videos.xml?channel_id=UC2eYFnH61tmytImy1mTYvhA \"~Luke Smith (YouTube)\"
# https://www.archlinux.org/feeds/news/" > "/home/$name/.config/newsboat/urls"
# make git ignore deleted LICENSE & README.md files
git update-index --assume-unchanged "/home/$name/README.md"

# 关掉系统的beep声音
systembeepoff

# 将系统的xkbmap改为norman布局
setsystemxkb

# 用户的默认shell使用fish
chsh -s /bin/fish "$name" >/dev/null 2>&1
# sudo -u "$name" mkdir -p "/home/$name/.cache/zsh/"

# fcitx5在x窗口启动的时候启动
sudo -u "$name" mkdir -p "/home/$name/.config/autostart/"
sudo -u "$name" cp /usr/share/applications/org.fcitx.Fcitx5.desktop ~/.config/autostart/

# dbus UUID must be generated for Artix runit.
# dbus-uuidgen > /var/lib/dbus/machine-id

# Use system notifications for Brave on Artix
# echo "export \$(dbus-launch)" > /etc/profile.d/dbus.sh

# Tap to click
[ ! -f /etc/X11/xorg.conf.d/40-libinput.conf ] && printf 'Section "InputClass"
        Identifier "libinput touchpad catchall"
        MatchIsTouchpad "on"
        MatchDevicePath "/dev/input/event*"
        Driver "libinput"
	# Enable left mouse button by tapping
	Option "Tapping" "on"
EndSection' > /etc/X11/xorg.conf.d/40-libinput.conf

# Fix fluidsynth/pulseaudio issue.
# grep -q "OTHER_OPTS='-a pulseaudio -m alsa_seq -r 48000'" /etc/conf.d/fluidsynth ||
# 	echo "OTHER_OPTS='-a pulseaudio -m alsa_seq -r 48000'" >> /etc/conf.d/fluidsynth

# Start/restart PulseAudio.
# pkill -15 -x 'pulseaudio'; sudo -u "$name" pulseaudio --start

# This line, overwriting the `newperms` command above will allow the user to run
# serveral important commands, `shutdown`, `reboot`, updating, etc. without a password.
newperms "%wheel ALL=(ALL) ALL #SOLUTY
%wheel ALL=(ALL) NOPASSWD: /usr/bin/shutdown,/usr/bin/reboot,/usr/bin/systemctl suspend,/usr/bin/wifi-menu,/usr/bin/mount,/usr/bin/umount,/usr/bin/pacman -Syu,/usr/bin/pacman -Syyu,/usr/bin/packer -Syu,/usr/bin/packer -Syyu,/usr/bin/systemctl restart NetworkManager,/usr/bin/rc-service NetworkManager restart,/usr/bin/pacman -Syyu --noconfirm,/usr/bin/loadkeys,/usr/bin/paru,/usr/bin/pacman -Syyuw --noconfirm"

# Last message! Install complete!
finalize
clear